package com.ruoyi.eqmonitor.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.eqmonitor.dispose.domain.OpentsdbTags;
import com.ruoyi.eqmonitor.domain.BizDeviceHistory;
import com.ruoyi.eqmonitor.dtos.OptDeviceDto;
import com.ruoyi.eqmonitor.exception.OpentsdbException;
import com.ruoyi.eqmonitor.exception.OpentsdbQueryException;
import com.ruoyi.eqmonitor.mapper.BizDeviceHistoryMapper;
import com.ruoyi.eqmonitor.service.IBizDeviceHistoryService;
import com.ruoyi.eqmonitor.service.IOptDeviceService;
import com.ruoyi.eqmonitor.utils.Constant;
import com.ruoyi.eqmonitor.utils.OpenTSDBUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.nio.reactor.IOReactorException;
import org.opentsdb.client.OpenTSDBClient;
import org.opentsdb.client.bean.request.SubQuery;
import org.opentsdb.client.bean.response.QueryResult;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;

/**
 * 设备监测历史表Service业务层处理
 *
 * @author breeze
 * @date 2022-12-15
 */
@Slf4j
@Service
public class BizDeviceHistoryServiceImpl extends ServiceImpl<BizDeviceHistoryMapper, BizDeviceHistory> implements IBizDeviceHistoryService {
    @Resource
    private OpenTSDBUtils openTSDBUtils;
    @Resource
    private IOptDeviceService iOptDeviceService;

    // cod设备
    public static final List<String> codSnCodes = new ArrayList<>();
    // 液位设备
    public static final List<String> ywSnCodes = new ArrayList<>();

    static {
        // 注入cod设备
        codSnCodes.add("7V7ET1");
        codSnCodes.add("3M1Y4H");
        codSnCodes.add("5V11PJ");
        codSnCodes.add("T067PZ");
        codSnCodes.add("931JSZ");
        // 注入液位设备
        ywSnCodes.add("ZQ922P");
        ywSnCodes.add("RTB906");
        ywSnCodes.add("4TRV24");
        ywSnCodes.add("FFP051");
        ywSnCodes.add("290TEN");
    }

    @Override
    public BizDeviceHistory selectBizDeviceHistoryById(Long id){
        return baseMapper.selectBizDeviceHistoryById(id);
    }

    @Override
    public List<BizDeviceHistory> selectBizDeviceHistoryList(BizDeviceHistory bizDeviceHistory){
        return baseMapper.selectBizDeviceHistoryList(bizDeviceHistory);
    }

    /**
     * 处理日历史分析
     */
    @Override
    @Async
    @Transactional(rollbackFor = Exception.class)
    public Future<String> analyseDailyHistory() {
        OpenTSDBClient queryClient = null;
        try {
            // 创建连接
            queryClient = openTSDBUtils.readClient();
            for (String codSnCode : codSnCodes) {
                saveHistoryByCode(codSnCode, Constant.MonitorInfo.M_0x0527.getCode(), queryClient);
            }
            for (String ywSnCode : ywSnCodes) {
                saveHistoryByCode(ywSnCode, Constant.MonitorInfo.M_0x05D1.getCode(), queryClient);
            }
        } catch (OpentsdbException | OpentsdbQueryException e) {
            throw new RuntimeException("查询opentsdb失败", e);
        } catch (IOReactorException e) {
            log.error("创建Opentsdb连接失败", e);
        } finally {
            if (queryClient != null) {
                //关闭连接
                try {
                    queryClient.gracefulClose();
                } catch (IOException e) {
                    log.error("关闭opentsdb连接失败", e);
                }
            }
        }
        return new AsyncResult<>("OK");
    }

    private void saveHistoryByCode(String snCode, String monitorCode, OpenTSDBClient queryClient) throws OpentsdbException, OpentsdbQueryException {
        OptDeviceDto deviceByCode = iOptDeviceService.getDeviceByCode(snCode);
        // 1. 创建snCodeFilter和monitorCode过滤器
        SubQuery.Filter snCodeFilter = OpenTSDBUtils.createSnCodeFilter(snCode);
        SubQuery.Filter monitorCodeFilter = OpenTSDBUtils.createMonitorCodeFilter(monitorCode);
        DateTime startTime = DateUtil.beginOfDay(DateUtil.offsetDay(new DateTime(), -1));
        DateTime endTime = DateUtil.endOfDay(DateUtil.offsetDay(new DateTime(), -1));
        List<QueryResult> resultList = new ArrayList<>();
        // 2. 执行查询
       /* List<QueryResult> resultList = openTSDBUtils.queryByOpentsdb(
                queryClient,
                startTime,
                endTime,
                SubQuery.Aggregator.AVG,
                "1dc-avg",
                snCodeFilter,
                monitorCodeFilter
        );*/
        log.info("设备编码: {} - {}, 数据条数: {}", snCode, monitorCode, resultList.size());
        for (QueryResult queryResult : resultList) {
            // 目的是将tags的base64转换为原始的字符串
            OpentsdbTags opentsdbTags = OpenTSDBUtils.decodeToBean(queryResult.getTags());
            Constant.MonitorInfo info = Constant.MonitorInfo.getInfoByCode(monitorCode);
            queryResult.getDps().forEach((stamp, number) -> {
                String monitorQuotaName = opentsdbTags.getMonitorName();
                String monitorUnit = opentsdbTags.getDataUnit();
                double value = NumberUtil.toBigDecimal(number).doubleValue();
                if (Constant.MonitorInfo.M_0x05D1.getCode().equals(info.getCode()) && value > 7) {
                    value = NumberUtil.div(value, 100);
                    monitorUnit = Constant.MonitorInfo.M_0x05D1.getUnit();
                }
                if (monitorQuotaName == null) {
                    Constant.MonitorInfo monitorInfoByCode = Constant.MonitorInfo.getMonitorInfoByCode(opentsdbTags.getMonitorCode());
                    if (monitorInfoByCode != null) {
                        monitorQuotaName = monitorInfoByCode.getName();
                        monitorUnit = monitorInfoByCode.getUnit();
                    }
                }

                BizDeviceHistory bizDeviceHistory = new BizDeviceHistory();
                bizDeviceHistory.setDeviceCode(deviceByCode.getDeviceCode());
                bizDeviceHistory.setDeviceTypeName(Constant.EquipmentType.getValueByCode(deviceByCode.getDeviceType()));
                bizDeviceHistory.setMonitorUnit(monitorUnit);
                bizDeviceHistory.setMonitorQuota(opentsdbTags.getMonitorCode());
                bizDeviceHistory.setMonitorData(NumberUtil.round(value, 3).toString());
                bizDeviceHistory.setStamp(stamp.toString());
                bizDeviceHistory.setDeviceType(deviceByCode.getDeviceType());
                bizDeviceHistory.setMonitorQuotaName(monitorQuotaName);
                bizDeviceHistory.setDate(DateUtil.parseDateTime(OpenTSDBUtils.deserialize(stamp)));
                save(bizDeviceHistory);
            });
        }
    }
}
